﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GWModflow.FileLayers
{
    public class UzfPackage : Package
    {
        public UzfPackage()
        {
            this._fileType = FileType.UZF;
            this.Fname = "solution.uzf";
            this.Nunit = 55;
        }


        private int _NUZTOP = 1; //补给和排放选项
        /// <summary>
        /// 补给和排放选项
        /// =1，补给和排放仅在模型顶层，这个选项假定陆地表面为顶层
        /// =2，补给和排放发生在特定层，层号由IUZFBND定义，假定陆地表面
        /// =3，补给和排放发生在最上面的激活的单元内，一个定水头可打破任何补给和排放并阻止任何渗漏。
        /// </summary>
        public int NUZTOP
        {
            get { return _NUZTOP; }
            set { _NUZTOP = value; }
        }

        private int _IUZFOPT = 1;//垂向水力传导系数来源
        /// <summary>
        /// 垂向水力传导系数来源
        /// 绝对值=1，垂向水力导水系数列在uzf1中使用VKs变量
        /// 绝对值= 2，表明垂向水力导水系数列在bcf或者lpf包中。
        /// 如果使用bcf包，则IUZFOPT的绝对值等于1。
        /// 如果IUZFOPT等于-1或-2，则渗流区的非饱和流忽略。
        /// </summary>
        public int IUZFOPT
        {
            get { return _IUZFOPT; }
            set { _IUZFOPT = value; }
        }
        private int _IRUNFLG = 0;//
        /// <summary>
        /// =0，表面水排放到陆地表面分流道径流段或湖泊
        /// != 0，表面水不排放到陆地表面分流道径流段或湖泊
        /// </summary>
        public int IRUNFLG
        {
            get { return _IRUNFLG; }
            set { _IRUNFLG = value; }
        }
        private int _IETFLG = 0;
        /// <summary>
        /// 如果等于0，则蒸散ET被模拟，反之则模拟
        /// != 0，不模拟蒸散
        /// </summary>
        public int IETFLG
        {
            get { return _IETFLG; }
            set { _IETFLG = value; }
        }
        private int _IUZFCB1 = 1;
        /// <summary>
        /// 保存标志1
        /// 正值，则仅保存表面水均衡信息
        /// 负值，神六和非饱和带区ET使用UBUDSV打印到非格式中
        /// </summary>
        public int IUZFCB1
        {
            get { return _IUZFCB1; }
            set { _IUZFCB1 = value; }
        }
        private int _IUZFCB2 = 2;
        /// <summary>
        /// 保存标志2
        /// </summary>
        public int IUZFCB2
        {
            get { return _IUZFCB2; }
            set { _IUZFCB2 = value; }
        }
        private int _NTRAIL2;
        /// <summary>
        /// 尾波的数目
        /// 尾波用来定义跟随在入渗率之后含水量剖面。
        /// 尾波的数目依赖于实际，但一个10-20之间的值通常是足够的。
        /// 值越大会降低均衡误差但会增加内存
        /// </summary>
        public int NTRAIL2
        {
            get { return _NTRAIL2; }
            set { _NTRAIL2 = value; }
        }
        private int _NSETS2;
        /// <summary>
        /// wave sets的数目
        /// 用来模拟多个入渗率时期。
        /// 对于大多数问题来说值等于20。
        /// 最大值不能超过NTRAIL2*NSETS2。
        /// </summary>
        public int NSETS2
        {
            get { return _NSETS2; }
            set { _NSETS2 = value; }
        }
        private int _NUZGAG = 0;
        /// <summary>
        /// 打印详细信息的单元数目  
        /// 默认为不打印
        /// </summary>
        public int NUZGAG
        {
            get { return _NUZGAG; }
            set { _NUZGAG = value; }
        }
        private double _SURFDEP;
        /// <summary>
        /// 波动的高度
        /// </summary>
        public double SURFDEP
        {
            get { return _SURFDEP; }
            set { _SURFDEP = value; }
        }


        private int[,] _IUZFBND;
        /// <summary>
        /// 用来定义aerial extent。
        /// 补给和排放发生的单元
        /// =0，表明补给和排放不模拟
        /// >=2，表明层的顶部是陆地表面
        /// =2，这层内发生补给和排放
        /// IUZFBND应该等于0在非激活的单元内核指定水头的单元内。
        /// 指定水头单元保罗IBOUND数组内的负值，CHD包的单元和FHB包中列在DATA 7中的单元
        /// </summary>
        public int[,] IUZFBND
        {
            get { return _IUZFBND; }
            set { _IUZFBND = value; }
        }

        //item3      
        private int[,] _IRUNBND;
        /// <summary>
        /// 用来定义SFR2中的河流段或者LAK3中的湖泊
        /// 正值定义为河流段
        /// 负值定义为湖泊
        /// </summary>
        public int[,] IRUNBND
        {
            get { return _IRUNBND; }
            set { _IRUNBND = value; }
        }



        private double[,] _VKS;
        /// <summary>
        /// 非饱和带中饱和垂向水力传导系数
        /// IF the absolute value of IUZFOPT = 1: Read item 4
        /// 垂垂向水力传导系数来源=1，即在uzf包中输入vks变量时，输入次变量
        /// 垂向水力传导系数时可选的当lpf或bcf包用来定义垂向水力传导系数(LT-1)
        /// </summary>
        public double[,] VKS
        {
            get { return _VKS; }
            set { _VKS = value; }
        }


        private double[,] _EPS;
        /// <summary>
        /// 每个网格单元的正实数用来定义非饱和带的Brooks-Corey epsilon
        /// Brooks-Corey epsilon用来表示含水量和水力传导系数的关系
        /// </summary>
        public double[,] EPS
        {
            get { return _EPS; }
            set { _EPS = value; }
        }

        private double[,] _THTS;
        /// <summary>
        /// 负实数
        /// 定义非饱和带的饱和含水量，单位(L3L-3).
        /// </summary>
        public double[,] THTS
        {
            get { return _THTS; }
            set { _THTS = value; }
        }

        private double[,] _THTI;
        /// <summary>
        /// 每个垂向列的网格单元定义初始含水量
        /// 单位是(L3L-3)，数值为负实数。
        /// </summary>
        public double[,] THTI
        {
            get { return _THTI; }
            set { _THTI = value; }
        }

        private bool _isHaveTransient;
        /// <summary>
        /// 是否为瞬态应力期,默认为F
        /// </summary>
        public bool IsHaveTransient
        {
            get { return _isHaveTransient; }
            set { _isHaveTransient = value; }
        }

        //item8
        private int _IUZROW;
        /// <summary>
        /// 一个整数等于非饱和带区域行数的信息将在每个时间步长内打印
        /// 当IFTUNIT为负值时，次变量不可用
        /// </summary>
        public int IUZROW
        {
            get { return _IUZROW; }
            set { _IUZROW = value; }
        }
        private int _IUZCOL;
        /// <summary>
        /// 列数的非饱和带信息将在每个时间步长打印。
        /// </summary>
        public int IUZCOL
        {
            get { return _IUZCOL; }
            set { _IUZCOL = value; }
        }
        private int _IFTUNIT;
        /// <summary>
        /// 输出文件的unit number
        /// 注：IFTUNIT必须有一个独特的值列在item8中。且文件号必须在modflow的命名文件中data
        /// </summary>
        public int IFTUNIT
        {
            get { return _IFTUNIT; }
            set { _IFTUNIT = value; }
        }
        private int _IUZOPT;
        /// <summary>
        /// 当IFTUNIT为负值时则不使用此变量。
        ///=1，打印时间、水头和非饱和带厚度…
        ///=2，同选项1出了渗流速度、补给、储存的变化
        ///=3，打印时间，水头等       
        /// </summary>
        public int IUZOPT
        {
            get { return _IUZOPT; }
            set { _IUZOPT = value; }
        }

        List<StressPeriodData> _stressPeriodDatas = new List<StressPeriodData>();
        /// <summary>
        /// 每个应力期数据
        /// </summary>
        public List<StressPeriodData> StressPeriodDatas
        {
            get { return _stressPeriodDatas; }
            set { _stressPeriodDatas = value; }
        } 


        public override void WriteFile(string path)
        {
            string content = "# HuanAnKeJi UZF File" + "\r\n";
            //item1
            content += this.NUZTOP + "  " + this.IUZFOPT + "  " + this.IRUNFLG + "  " + this.IETFLG + "  " + this.IUZFCB1 + "  " + this.IUZFCB2 + "  " + this.NTRAIL2 + "  " + this.NSETS2 + "  " + this.NUZGAG + "  " + this.SURFDEP + "\r\n";
            //item2
            if (IsConstant(this.IUZFBND))
            {
                content += "CONSTANT " + string.Format("{0,10}", this.IUZFBND[0, 0]) + "\r\n";
            }
            else
            {
                
                string str = "";
                if (GetArrayString(this.IUZFBND, ref str))
                {
                    content += "INTERNAL   1 (FREE)  9" + "\r\n";
                    content += str;
                }
            }
            //item3
            if (this.IRUNFLG > 0)
            {
                if (IsConstant(this.IRUNBND))
                {
                    content += "CONSTANT " + string.Format("{0,10}", this.IRUNBND[0, 0]) + "\r\n";
                }
                else
                {
                   
                    string str = "";
                    if (GetArrayString(this.IRUNBND, ref str))
                    {
                        content += "INTERNAL   1 (FREE)  9" + "\r\n";
                        content += str;
                    }
                }
            }
            //item4
            if (this.IUZFOPT == 1)
            {
                if (IsConstant(this.VKS))
                {
                    content += "CONSTANT " + string.Format("{0,10}", this.VKS[0, 0]) + "\r\n";
                }
                else
                {
                    
                    string str = "";
                    if (GetArrayString(this.VKS, ref str))
                    {
                        content += "INTERNAL   1 (FREE)  19" + "\r\n";
                        content += str;
                    }
                }
            }
            //item5
            if (IsConstant(this.EPS))
            {
                content += "CONSTANT " + string.Format("{0,10}", this.EPS[0, 0]) + "\r\n";
            }
            else
            {
              
                string str = "";
                if (GetArrayString(this.EPS, ref str))
                {
                    content += "INTERNAL   1 (FREE)  19" + "\r\n";
                    content += str;
                }
            }
            //item6
            if (IsConstant(this.THTS))
            {
                content += "CONSTANT " + string.Format("{0,10}", this.THTS[0, 0]) + "\r\n";
            }
            else
            {
               
                string str = "";
                if (GetArrayString(this.THTS, ref str))
                {
                    content += "INTERNAL   1 (FREE)  19" + "\r\n";
                    content += str;
                }
            }
            //item7
            if (this.IsHaveTransient)
            {
                if (IsConstant(this.THTI))
                {
                    content += "CONSTANT " + string.Format("{0,10}", this.THTI[0, 0]) + "\r\n";
                }
                else
                {

                    string str = "";
                    if (GetArrayString(this.THTI, ref str))
                    {
                        content += "INTERNAL   1 (FREE)  19" + "\r\n";
                        content += str;
                    }
                }
            }
            //item8 当NUZGAG大于 0时才用此组，本项目决定不使用此组，所以没写item8组的情况 this.NUZGAG = 0;
            //item9 9组以后是每个应力期一组数据
            string  str1="";
            foreach (StressPeriodData item in this .StressPeriodDatas)
            {
                str1 += item.NUZF1 + "\r\n";
                if (item.NUZF1 >= 0)
                {
                    if (IsConstant(item.FINF))
                    {
                        str1 += "CONSTANT " + string.Format("{0,10}", item.FINF[0, 0]) + "\r\n";
                    }
                    else
                    {
                       
                        string str = "";
                        if (GetArrayString(item.FINF, ref str))
                        {
                            str1 += "INTERNAL   1 (FREE)  19" + "\r\n";
                            str1 += str;
                        }
                    }
                }
                if (this.IETFLG > 0)
                {
                    //item11
                    str1 += item.NUZF2 + "\r\n";
                    //item12
                    if (item.NUZF2 >= 0)
                    {
                        if (IsConstant(item.PET))
                        {
                            str1 += "CONSTANT " + string.Format("{0,10}", item.PET[0, 0]) + "\r\n";
                        }
                        else
                        {
                            
                            string str = "";
                            if (GetArrayString(item.PET, ref str))
                            {
                                str1 += "INTERNAL   1 (FREE)  19" + "\r\n";
                                str1 += str;
                            }
                        }
                    }
                    //item13
                    str1 += item.NUZF3 + "\r\n";
                    //item14
                    if (item.NUZF3 >= 0)
                    {
                        if (IsConstant(item.EXTDP))
                        {
                            str1 += "CONSTANT " + string.Format("{0,10}", item.EXTDP[0, 0]) + "\r\n";
                        }
                        else
                        {
                           
                            string str = "";
                            if (GetArrayString(item.EXTDP, ref str))
                            {
                                str1 += "INTERNAL   1 (FREE)  19" + "\r\n";
                                str1 += str;
                            }
                        }
                    }
                    //item15
                    str1 += item.NUZF4 + "\r\n";
                    //item16
                    if (item.NUZF4 >= 0)
                    {
                        if (IsConstant(item.EXTWC))
                        {
                            str1 += "CONSTANT " + string.Format("{0,10}", item.EXTWC[0, 0]) + "\r\n";
                        }
                        else
                        {
                           
                            string str = "";
                            if (GetArrayString(item.EXTWC, ref str))
                            {
                                str1 += "INTERNAL   1 (FREE)  19" + "\r\n";
                                str1 += str;
                            }
                        }
                    }

                }
            }

            content += str1;
            string fname = path + this.Fname;
            FXnaInfrastructure.FileHelper.WriteFile(fname, content);
        }

    }
    public class StressPeriodData
    {
        private int _NUZF1;
        /// <summary>
        /// 陆表面入渗速率读取标志
        /// NUZF1>=0，指定陆表面入渗速率
        /// NUZF1小于0，入渗速率使用上一应力期参数
        /// </summary>
        public int NUZF1
        {
            get { return _NUZF1; }
            set { _NUZF1 = value; }
        }

        private double[,] _FINF;
        /// <summary>
        /// 定义每个网格单元的入渗速率(LT-1)
        /// 如果FINF大于垂向水力传导系数则FINF等于垂向水力传导系数。
        /// 多余水分分离为河流和湖泊如果IRUNFLG不等于0，当SFR2 or LAK3 is active.        /// 
        /// </summary>
        public double[,] FINF
        {
            get { return _FINF; }
            set { _FINF = value; }
        }

        //If IETFLG > 0: Read Items 11 through 16 以下
        private int _NUZF2;
        /// <summary>
        /// ET demand rates读取标志
        /// NUZF2≥0，则定义ET demand rates
        /// NUZF2小于0，使用上一应力期数据
        /// </summary>
        public int NUZF2
        {
            get { return _NUZF2; }
            set { _NUZF2 = value; }
        }
        private double[,] _PET;
        /// <summary>
        /// 单元ET demand rates
        /// 单位为(L1T-1)
        /// If NUZF2 ≥ 0
        /// </summary>
        public double[,] PET
        {
            get { return _PET; }
            set { _PET = value; }
        }

        private int _NUZF3;
        /// <summary>
        /// ET消失深度
        /// NUZF3≥0，需定义ET消失深度
        ///  NUZF3小于0，使用上一应力期数据
        /// </summary>
        public int NUZF3
        {
            get { return _NUZF3; }
            set { _NUZF3 = value; }
        }
        private double[,] _EXTDP;
        /// <summary>
        /// 每个网格单元的ET消失深度
        /// NUZF3≥0，需定义ET消失深度    
        /// </summary>
        public double[,] EXTDP
        {
            get { return _EXTDP; }
            set { _EXTDP = value; }
        }
        private int _NUZF4;
        /// <summary>
        /// extinction water content的读取标志
        /// NUZF4≥0，需定义ET消失深度
        /// NUZF4小于0，使用上一应力期数据
        /// </summary>
        public int NUZF4
        {
            get { return _NUZF4; }
            set { _NUZF4 = value; }
        }
        private double[,] _EXTWC;
        /// <summary>
        /// 网格单元的extinction water content
        /// If NUZF4 ≥ 0
        /// Note 8: EXTWC must have a value between (THTS-Sy) and THTS, where Sy is the specific yield specified in either the LPF or BCF Package
        /// </summary>
        public double[,] EXTWC
        {
            get { return _EXTWC; }
            set { _EXTWC = value; }
        }
    }
}
